package com.morgan.basemodule.utils

import com.google.gson.internal.`$Gson$Types`
import com.google.gson.reflect.TypeToken
import java.lang.reflect.ParameterizedType
import java.lang.reflect.Type


/**
 *description： 参照 com.google.gson.reflect.TypeToken
 *<br>author：caowugao
 *<br>time：2021/4/6 0006 16:14
 */
class GsonTypeToken private constructor(){

    companion object {


        private fun genericSuperParameterizedType(currentClass: Class<*>?): ParameterizedType? {
            val superclass = currentClass?.genericSuperclass ?: return null
            if (superclass !is ParameterizedType) {
                return genericSuperParameterizedType(currentClass.superclass)
            }
            return superclass
        }

        /**
         * 泛型擦拭法使得Generic无法获取自己的Generic Type类型.
         * 实例化以后Class里面就不包括T的信息了，对于Class而言T已经被擦拭为Object,
         * 而真正的T参数被转到使用T的方法（或者变量声明或者其它使用T的地方）里面（如果没有那就没有存根），所以无法反射到T的具体类别，也就无法得到T.class。
         * 而getGenericSuperclass()是Generic继承的特例，对于这种情况子类会保存父类的Generic参数类型，
         * 返回一个ParameterizedType，这时可以获取到父类的T.class了，这也正是子类确定应该继承什么T的方法。
         *
         * 获取  父类的泛型参数  的Type
         * index:表示该泛型参数在父类的位置。比如 A<T,E..>.从0开始
         */
        fun getSuperclassTypeParameter(currentClass: Class<*>, index: Int = 0): Type? {
            return try {
//                    val superclass = currentClass.genericSuperclass!!
//                    if (superclass is Class<*>) {
//                        throw RuntimeException("currentClass:$currentClass super class Missing type parameter.")
//                    }
                val superclass = genericSuperParameterizedType(currentClass)
                val parameterized = superclass as ParameterizedType
                `$Gson$Types`.canonicalize(parameterized.actualTypeArguments[index])
            } catch (e: Throwable) {
                e.printStackTrace()
                null
            }
        }

        /**
         * 获取  父类的泛型参数  的Class对象
         * index:表示该泛型参数在父类的位置。比如 A<T,E..>.从0开始
         */
        fun <T> getSuperclassTypeParameterClass(currentClass: Class<*>, index: Int = 0): Class<T>? {
            val type = getSuperclassTypeParameter(currentClass, index)
            return if (type != null) (getRawType(type)) as? Class<T> else null
        }

        /**
         * 获取原始的类型
         */
        fun getRawType(type: Type): Type? {
            //用于子类有泛型，父类也有泛型的情况 如：A<X> : B<X>(){} sun.reflect.generics.reflectiveObjects.TypeVariableImpl
            if (type.javaClass.name == "sun.reflect.generics.reflectiveObjects.TypeVariableImpl") {
                return getRealTypeClassByTypeVariableImpl(type)
            }
            return `$Gson$Types`.getRawType(type)
        }

        private fun getRealTypeClassByTypeVariableImpl(type: Type): Class<*>? {
            return try {
                val boundASTsField =
                    type.javaClass.getDeclaredField("boundASTs") //类型 sun.reflect.generics.tree.FieldTypeSignature[]
                boundASTsField.isAccessible = true
                val boundASTsArr = boundASTsField.get(type)
                val classTypeSignature = (boundASTsArr as Array<Any>)[0] //ClassTypeSignature
                val pathFiled = classTypeSignature.javaClass.getDeclaredField("path")
                pathFiled.isAccessible = true
                val list =
                    pathFiled.get(classTypeSignature) as List<Any> //ArrayList<SimpleClassTypeSignature>
                val simpleClassTypeSignature = list[0] //SimpleClassTypeSignature
                val nameField = simpleClassTypeSignature.javaClass.getDeclaredField("name")
                nameField.isAccessible = true
                val name = nameField.get(simpleClassTypeSignature) as String
                Class.forName(name)
            } catch (e: Throwable) {
                e.printStackTrace()
                null
            }
        }

        /**
         * 获取  父类的泛型参数  的 TypeToken
         * index:表示该泛型参数在父类的位置。比如 A<T,E..>.从0开始
         */
        fun getTypeToken(currentClass: Class<*>, index: Int = 0): TypeToken<*>? {
            val type = getSuperclassTypeParameter(currentClass, index)
            return if (type != null) TypeToken.get(type) else null
        }

    }
}